<?php
/**
 * @file template.class.php
 * @author 禅元天道 chanyuantiandao@126.com
 * @DateTime 2022-01-18 11:12
 * @brief 模板文件处理类
 */

!defined('CHAN_CMS') && exit('非法访问！');

class Template
{
    private $config;
    private static $_instance = null;

    public static function getInstance()
    {
        if(is_null(self::$_instance) || !self::$_instance instanceof self){
            self::$_instance = new self;
        }
        return self::$_instance;
    }

    private function __clone(){}

    private function __construct(){
        $tplConfig = array(
            'compress_php' => true,
            'compile_path' => FileHelper::joinPath('data','cache',getMd5('compile_path', 12))
        );
        if(App::config('template') != null){
            $tplConfig = array_merge($tplConfig, App::config('template'));
        }
        $this->config = $tplConfig;
    }

    function __destruct() { }

    private function findAllTags($pattern, $content) {
        preg_match_all("/".$this->config['start_tag'].$pattern.$this->config['end_tag']."/s", $content, $match);
        return $match;
    }
    
    public function parseFile($tpl){
        $tplFile = FileHelper::joinPathWithRoot($this->config['path'], $this->config['theme']).$tpl.$this->config['suffix'];
        $compile_file_path = $this->config['compile_path'].md5($tplFile).'.php';
        if(file_exists($tplFile)){
            if(file_exists($compile_file_path)){
                $tplModifyTime = filemtime($tplFile);
                $lastCompileTime = filemtime($compile_file_path);
                if($tplModifyTime && $lastCompileTime && ($lastCompileTime > $tplModifyTime)){
                    return $compile_file_path;
                }
            }

            $tplContent = file_get_contents($tplFile);
            $matches = $this->findAllTags('include\s+file="(.+?)"', $tplContent);
            foreach ($matches[1] as $key => $match){
                $tempPath = FileHelper::joinPathWithRoot($this->config['path'], $this->config['theme']).str_replace(array(':', '\/'), DIRECTORY_SEPARATOR, $match);
                if(file_exists($tempPath)){
                    $tplContent = str_replace($matches[0][$key], file_get_contents($tempPath),$tplContent);
                }else{
                    $tplContent = str_replace($matches[0][$key], '', $tplContent);
                }
            }

            $compile_php_content = $this->config['compress_php'] ? compressCode($this->parse($tplContent), 'php') : $this->parse($tplContent);

            if(!file_exists($this->config['compile_path']))
                mkdir($this->config['compile_path'], 0666, true);


            if(file_put_contents($compile_file_path, $compile_php_content) > 0){
                return $compile_file_path;
            }else{
                return false;
            }
        }else{
            throw new ChanException('模板文件'.$this->config['theme'].'/'.$tpl.$this->config['suffix'].'不存在！');
        }
    }

    private function parse($content) {

        $content = preg_replace_callback(
            '/'.$this->config['start_tag'].'(.+?)'.$this->config['end_tag'].'/s',
            function($matches){
                return preg_replace_callback('/\$(\S+)/s', function($ma){return str_replace('.','->', $ma[0]);}, $matches[0]);
            },
            $content);

        $regex = array(
            // foreach解析
            '/'.$this->config['start_tag'].'foreach\s+\$(.+?)\s+in\s+\$(.+?)'.$this->config['end_tag'].'/s' => /** @lang {foreach $item in $items} */'<?php $tpl_index = 1; foreach($tpl_$2 as $tpl_key => $tpl_$1){ ?>',
            '/'.$this->config['start_tag'].'\/foreach\s+\$(\S+)'.$this->config['end_tag'].'/s' => /** @lang {/foreach $item} */'<?php ++$tpl_index;} unset($tpl_index);unset($tpl_$1); ?>',

            // if..elseif..else解析
            '/'.$this->config['start_tag'].'(elif|else\s?if)\s+\$(.+?)\s?([=<>!]+)\s?(\$(.+?)|\"(.+?)\")'.$this->config['end_tag'].'/s' => /** @lang {(elif|else if) $data==($value|"测试条件")} */'<?php } else if($tpl_$2 $3 $4){ ?>',
            '/'.$this->config['start_tag'].'if\s+\$(\w+)\s?([=<>!]+)\s?(\$(\w+)|\"(.+?)\")'.$this->config['end_tag'].'/s' => /** @lang {if $data==($value|"测试条件")} */'<?php if($tpl_$1 $2 $3){ ?>',
            '/'.$this->config['start_tag'].'else\s*'.$this->config['end_tag'].'/s' => /** @lang {else} */'<?php } else { ?>',
            '/'.$this->config['start_tag'].'\/if'.$this->config['end_tag'].'/s' => /** @lang {/if} */'<?php } ?>',

            // echo 解析
            '/'.$this->config['start_tag'].'\$(.+?)'.$this->config['end_tag'].'/is' => /** @lang {$data} */'<?php echo $tpl_$1; ?>',
        );
        return preg_replace(array_keys($regex), array_values($regex), $content);
    }


}